#include "OpenGLTextureManager.h"
#include "OpenGLTexture.h"

#ifdef __COMPILE_WIN32__
	#include <Windows.h>
#endif

#include <GL/gl.h>
#include <GL/glu.h>
#include "../../ReadedFont.h"

COpenGLTextureManager::COpenGLTextureManager()
{
}

COpenGLTextureManager::~COpenGLTextureManager()
{
}

void COpenGLTextureManager::SetTextureCreationParams(STextureCreationParams *ntcp)
{
    Actualtcp.Copy(ntcp);
}

ITexture *COpenGLTextureManager::CreateTextureBeta(IImage *Image,CColor color,vector2du32 Len,STextureCreationParams *tcp)
{
	u32 *RealPixels;
	u32 *Buffer = NULL;
	if (Image)
		Buffer = Image->GetBuffer();
	STextureCreationParams *tcpuse = (tcp?tcp:&Actualtcp);
	u32 Dir=0;
	u32 Color;
	u32 ColorTrans=0;
	u32 OriginX=0;
	u32 OriginY=0;
	u32 DestX = Len.X;
	u32 DestY = Len.Y;

	if (tcpuse->UseTransparentColor)
		ColorTrans = tcpuse->TransparentColor.GetColorUInt(CT_RGB);

	if (Buffer)
	{
		DestX = Image->GetW();
		DestY = Image->GetH();
	}

	if (tcpuse->UseOriginAndDest)
	{
		OriginX = (u32)tcp->Origin.X;
		OriginY = (u32)tcp->Origin.Y;
		DestX = (u32)tcp->Dest.X;
		DestY = (u32)tcp->Dest.Y;
	}

	u32 LenX = DestX - OriginX;
	u32 LenY = DestY - OriginY;

	RealPixels = new u32[LenX*LenY];
	for (u32 y=OriginY;y<DestY;y++)
	{
		for (u32 x=OriginX;x<DestX;x++)
		{
			RealPixels[Dir]=Buffer[y*Image->GetW()+x];
			Dir++;
		}
	}

	Dir=0;

	for (u32 y=0;y<LenX;y++)
	{
		for (u32 x=0;x<LenY;x++)
		{
			Color = RealPixels[Dir];
			Color &= 0x00ffffff;
			bool Trans = false;

			if (Color == ColorTrans && tcpuse->UseTransparentColor)
			{
				Color = 0x00000000;
				Trans=true;
			}

			if (!Trans)
				Color = (0xff<<24) | Color;

			RealPixels[Dir] = Color;
			Dir++;
		}
	}

	u32 LenW = LenX;
	u32 LenH = LenY;

	u32 texture;

	NewTexture(&texture);
	glBindTexture(GL_TEXTURE_2D,texture);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,tcpuse->Linear?GL_LINEAR:GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,tcpuse->Linear?GL_LINEAR:GL_NEAREST);

	glTexImage2D(GL_TEXTURE_2D,0,4,LenW,LenH,0,GL_RGBA,GL_UNSIGNED_BYTE,RealPixels);

	COpenGLTexture *Ret = new COpenGLTexture();
	Ret->SetLen(vector2du32(LenW,LenH));
	Ret->SetTexture(texture);

	DEALLOCATEARRAY(RealPixels);

	return Ret;
}

ITexture *COpenGLTextureManager::CreateTextureFromImage(IImage *Image,STextureCreationParams *tcp)
{
	u32 *Buffer = Image->GetBuffer();
	STextureCreationParams *tcpuse = (tcp?tcp:&Actualtcp);

	if (Buffer)
	{
		u32 *RealPixels;

		u32 Dir=0;
		u32 Color;
		u32 ColorTrans=0;
		u32 OriginX=0;
		u32 OriginY=0;
		u32 DestX = Image->GetW();
		u32 DestY = Image->GetH();

		if (tcpuse->UseTransparentColor)
			ColorTrans = tcpuse->TransparentColor.GetColorUInt(CT_RGB);
		if (tcpuse->UseOriginAndDest)
		{
			OriginX = (u32)tcpuse->Origin.X;
			OriginY = (u32)tcpuse->Origin.Y;
			DestX = (u32)tcpuse->Dest.X;
			DestY = (u32)tcpuse->Dest.Y;
		}

		u32 LenX = DestX - OriginX;
		u32 LenY = DestY - OriginY;

		RealPixels = new u32[LenX*LenY];
		for (u32 y=OriginY;y<DestY;y++)
		{
			for (u32 x=OriginX;x<DestX;x++)
			{
				RealPixels[Dir]=Buffer[y*Image->GetW()+x];
				Dir++;
			}
		}

		Dir=0;

		for (u32 y=0;y<LenX;y++)
		{
			for (u32 x=0;x<LenY;x++)
			{
				Color = RealPixels[Dir];
				Color &= 0x00ffffff;
				bool Trans = false;

                if (Color == ColorTrans && tcpuse->UseTransparentColor)
				{
					Color = 0x00000000;
					Trans=true;
				}

				if (!Trans)
					Color = (0xff<<24) | Color;

				RealPixels[Dir] = Color;
				Dir++;
			}
		}

		u32 LenW = LenX;
		u32 LenH = LenY;

		u32 texture;

		NewTexture(&texture);
		glBindTexture(GL_TEXTURE_2D,texture);

		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,tcpuse->Linear?GL_LINEAR:GL_NEAREST);
		glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,tcpuse->Linear?GL_LINEAR:GL_NEAREST);

		glTexImage2D(GL_TEXTURE_2D,0,4,LenW,LenH,0,GL_RGBA,GL_UNSIGNED_BYTE,RealPixels);

		COpenGLTexture *Ret = new COpenGLTexture();
		Ret->SetLen(vector2du32(LenW,LenH));
		Ret->SetTexture(texture);

		DEALLOCATEARRAY(RealPixels);

		return Ret;
	}

	return NULL;
}

ITexture *COpenGLTextureManager::CreateEmptyTexture(CColor color,vector2du32 Len,STextureCreationParams *tcp)
{
	u32 *RealPixels;
	STextureCreationParams *tcpuse = (tcp?tcp:&Actualtcp);

	u32 Dir=0;
	u32 Color;
	u32 ColorTrans=0;
	u32 OriginX=0;
	u32 OriginY=0;
	u32 DestX = Len.X;
	u32 DestY = Len.Y;

	if (tcpuse->UseTransparentColor)
		ColorTrans = tcpuse->TransparentColor.GetColorUInt(CT_RGB);
	if (tcpuse->UseOriginAndDest)
	{
		OriginX = (u32)tcp->Origin.X;
		OriginY = (u32)tcp->Origin.Y;
		DestX = (u32)tcp->Dest.X;
		DestY = (u32)tcp->Dest.Y;
	}

	u32 LenX = DestX - OriginX;
	u32 LenY = DestY - OriginY;

	RealPixels = new u32[LenX*LenY];
	for (u32 y=OriginY;y<DestY;y++)
	{
		for (u32 x=OriginX;x<DestX;x++)
		{
		    RealPixels[Dir]=color.GetColorUInt(CT_RGBA);
			Dir++;
		}
	}

	Dir=0;

	for (u32 y=0;y<LenX;y++)
	{
		for (u32 x=0;x<LenY;x++)
		{
			Color = RealPixels[Dir];
			Color &= 0x00ffffff;
			bool Trans = false;

			if (Color == ColorTrans && tcpuse->UseTransparentColor)
			{
				Color = 0x00000000;
				Trans=true;
			}

			if (!Trans)
				Color = (0xff<<24) | Color;

			RealPixels[Dir] = Color;
			Dir++;
		}
	}

	u32 LenW = LenX;
	u32 LenH = LenY;

	u32 texture;

	NewTexture(&texture);
	glBindTexture(GL_TEXTURE_2D,texture);

	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,tcpuse->Linear?GL_LINEAR:GL_NEAREST);
	glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,tcpuse->Linear?GL_LINEAR:GL_NEAREST);

	glTexImage2D(GL_TEXTURE_2D,0,4,LenW,LenH,0,GL_RGBA,GL_UNSIGNED_BYTE,RealPixels);

	COpenGLTexture *Ret = new COpenGLTexture();
	Ret->SetLen(vector2du32(LenW,LenH));
	Ret->SetTexture(texture);

	DEALLOCATEARRAY(RealPixels);

	return Ret;
}

IFont *COpenGLTextureManager::CreateFontFromImage(IImage *Image,STextureCreationParams *tcp)
{
	bool Delete=false;

	if (!tcp)
	{
		tcp = new STextureCreationParams;
		(tcp->TransparentColor).SetRGB(1.0,0.0,1.0);
		tcp->UseTransparentColor = true;
		tcp->Linear = false;
		Delete = true;
	}

//	ITexture *Texture = CreateTextureFromImage(Image,tcp);
	CReadedFont *TempFont = new CReadedFont(Image);

	if (Delete)
	{
		delete tcp;
		tcp = NULL;
	}

	return TempFont;
}

void COpenGLTextureManager::NewTexture(u32 *tex)
{
	glGenTextures(1,tex);
	IncReference(*tex);
}

bool COpenGLTextureManager::IncReference(u32 Index)
{
	bool Result=true;
	while (TextureReferences.size()<(Index+1))
	{
		Result = false;
		TextureReferences.push_back(0);
	}

	if (TextureReferences[Index] == 0)
		pLogDebug << "Creating texture with index " << Index << "..." << endl;
	else
		pLogDebug << "Texture with index " << Index << ", incrementing reference to " << TextureReferences[Index] + 1 << "..." << endl;

	TextureReferences[Index]++;
	return Result;
}

bool COpenGLTextureManager::DecReference(u32 Index)
{
	if (TextureReferences.size()>Index)
	{
		if (TextureReferences[Index] > 0)
		{
			TextureReferences[Index]--;
			pLogDebug << "Dereferencing texture " << Index << " to " << TextureReferences[Index] << "..." << endl;
		}
		else
			pLogDebug << "Dereferencing texture " << Index << " to " << 0 << "..." << endl;

		if (TextureReferences[Index] == 0)
			return true;
	}

	return false;
}

ITexture *COpenGLTextureManager::CloneTexture(ITexture *Text)
{
	COpenGLTexture *Ret = new COpenGLTexture();
	Ret->SetLen(vector2du32(Text->GetLen()));
	Ret->SetTexture(Text->GetTextureID());
	IncReference(Text->GetTextureID());
	return Ret;
}

IFont *COpenGLTextureManager::CloneFont(IFont *font)
{
}

bool COpenGLTextureManager::DeleteTexture(ITexture *Tex)
{
	u32 Id = Tex->GetTextureID();
	bool Ret = DecReference(Tex->GetTextureID());
	DEALLOCATE(Tex);

	if (Ret)
	{
		// Deallocating is necessary.
		glDeleteTextures(1,&Id);
		pLogDebug << "Destroying texture with ID: " << Id << endl;
		return true;
	}

	return false;
}

bool COpenGLTextureManager::DeleteFont(IFont *Font)
{
}
